<?php

namespace app\queue;

use think\Log;
use think\module\Module;
use support\bootstrap\Redis;
use Webman\Stomp\Client;
use Webman\Stomp\Consumer;
use common\service\UserService;
use Workerman\Stomp\AckResolver;

abstract class BaseConsumer implements Consumer
{
    /**
     * @var false|string
     */
    private $consumerName;

    // 值为 client 时需要调用$ack_resolver->ack()告诉服务端已经成功消费
    // 值为 auto   时无需调用$ack_resolver->ack()
    public $ack = 'client';

    public function __construct()
    {
        $this->consumerName = get_called_class();
    }

    /**
     * 真正的消费执行体
     * @param $data
     * @return mixed
     */
    abstract public function doConsume($data);

    /**
     * 初始化
     */
    public function init($param)
    {
        Module::init();

        //  支持预设xu
        if (!empty($param['xu'])) {
            try {
                request()->getXUserInfo($param['xu']);
                UserService::getInstance()->parseXUserInfoAndPresetRequest($param['xu']);
                $batchNumber = request()->getBatchNumber();
                $createdByUUID = request()->getUserUUID();
            } catch (\Throwable $e) {
                trace($param['xu'] . PHP_EOL . format_exception_info($e), 'ERR');
                // 预设好 batchNumber 和 createdBy
                $batchNumber = sprintf("consumer:%s:%s:%s-%d", C('belong_system'), $this->consumerName, get_random_str(8), time());
                $createdByUUID = sprintf("%s-%s", C('belong_system'), "console-consumer");
            }
        } else {
            // 预设好 batchNumber 和 createdBy
            $batchNumber = sprintf("consumer:%s:%s:%s-%d", C('belong_system'), $this->consumerName, get_random_str(8), time());
            $createdByUUID = sprintf("%s-%s", C('belong_system'), "console-consumer");
        }
        $batchNumber = empty($batchNumber) ? 'un_authorized' : $batchNumber;
        request()->getBatchNumber($batchNumber);
        request()->getUserUUID($createdByUUID);

        APP_DEBUG && G($this->consumerName . request()->getBatchNumber() . '_start');
        APP_DEBUG && trace('[ ' . $this->consumerName . ' ] --START--', "INFO");
    }

    /**
     * 处理消费完毕后 event 消费推送
     */
    public function close()
    {
        if (!empty(request()->getBatchNumber()) && Redis::lLen(request()->getBatchNumber())) {
            Client::send('event', build_queue_data_with_xu(["event_data_key" => \request()->getBatchNumber()]));
        }
        APP_DEBUG && G($this->consumerName . request()->getBatchNumber() . '_end');
        APP_DEBUG && trace('[ ' . get_called_class() . ' ] --END-- [ RunTime:' . G($this->consumerName . request()->getBatchNumber() . '_start', $this->consumerName . request()->getBatchNumber() . '_end', 6) . 's ]', "INFO");
        Log::save();
    }

    /**
     * 消费方法 封装初始化和close
     * @param $data
     * @param AckResolver|null $ackResolver
     */
    public function consume($data, AckResolver $ackResolver = null)
    {
        $param = json_decode($data, true);
        $this->init($param);
        try {
            $this->doConsume($param);
            // 告诉服务端，已经成功消费
            $ackResolver->ack(); // ack为 auto时可以省略此调用
        } finally {
            $this->close();
        }
    }

}
